/**
 *******************************************************************************
 * @file can_driver.c
 * @author .ISS_AUTO (hudandan@issauto.com)
 * @date 2025-05-10
 *
 * @brief Project: AK601
 *
 * @copyright Copyright (c) 2025 ISSAUTO TECH Co., Ltd. All rights reserved.
 *
 *******************************************************************************
 */
/* Includes ------------------------------------------------------------------*/
#include "can_driver.h"

/* Private variables ---------------------------------------------------------*/
CAN_DriverTypeDef can1_driver;

/* Private functions ---------------------------------------------------------*/

/*******************************************************************************d
 *                             CAN Driver
********************************************************************************/

/**
 * @brief Send the CANx Message.
 *
 * @param dcan
 * @param id
 * @param msg
 * @param dlc
 * @return The number of the mailbox that is used for transmission or CAN_TxSTS_NoMailBox if there is no empty mailbox.
 */
static uint8_t CANx_Tx_Message(struct __CAN_DriverTypeDef *dcan, uint32_t id, uint8_t *msg, uint8_t dlc)
{
    uint8_t transmit_mailbox = CAN_TxSTS_NoMailBox;
    int i;

    if (dlc > 8) {
        dlc = 8; //!< input length error
    }

    if (msg != NULL) {
        dcan->TxMessage.StdId = id;
        dcan->TxMessage.IDE   = CAN_ID_STD;    //!< 标准帧
        dcan->TxMessage.RTR   = CAN_RTRQ_DATA; //!< 设置为数据帧
        dcan->TxMessage.DLC   = dlc;           //!< 数据长度, can报文规定最大的数据长度为8字节

        for (i = 0; i < dlc; i ++) {
            dcan->TxMessage.Data[i] = msg[i];
        }

        transmit_mailbox = CAN_TransmitMessage(dcan->Instance, &(dcan->TxMessage)); //!< 返回这个信息请求发送的邮箱号0,1,2或没有邮箱申请发送no_box
    }

    return transmit_mailbox;
}

/**
 * @brief Send the CAN2 Message.
 *
 * @param id
 * @param msg
 * @param dlc
 * @return The number of the mailbox that is used for transmission or CAN_TxSTS_NoMailBox if there is no empty mailbox.
 */
uint8_t CAN1_Tx_Message(uint32_t id, uint8_t *msg, uint8_t dlc)
{
    return CANx_Tx_Message(&can1_driver, id, msg, dlc);
}

/**
 * @brief Rx Message of the CAN2
 *
 * @return CanRxMessage*
 */
CanRxMessage CAN1_Rx_Message(void)
{
    return can1_driver.RxMessage;
}

/*******************************************************************************
 *                             CAN Configuration
********************************************************************************/

/**
 * @brief Configures CAN2 Filer.
 *
 * @param FilterID
 * @param FilterID_Num It ranges from 0 to 13.
 */
void CAN1_Filter_Init(uint32_t *FilterID, uint8_t FilterID_Num)
{
    if ((FilterID != NULL) && (FilterID_Num < 13)) {

        CAN_FilterInitType CAN_FilterInitStructure;

        for (size_t i = 0; i < FilterID_Num; i++) {

            /* CAN filter init */
            CAN_FilterInitStructure.Filter_Num            = i;
            CAN_FilterInitStructure.Filter_Mode           = CAN_Filter_IdMaskMode; //!< 0: 工作在标识符屏蔽位模式
            CAN_FilterInitStructure.Filter_Scale          = CAN_Filter_32bitScale; //!< 过滤器位宽为单个32位

            /**
             * @note 使能报文标示符过滤器按照标示符的内容进行比对过滤，
             *        标准ID不是如下的就抛弃掉，是的话，会存入FIFO0
             *
             *      标准帧 11bits : STDID[10:0]
             *      扩展帧 18bits : EXTID[17:0]
             */
            CAN_FilterInitStructure.Filter_HighId         = (((uint32_t)FilterID[i] << 21) >> 16); //!< 要过滤的ID高位
            CAN_FilterInitStructure.Filter_LowId          = (((uint32_t)FilterID[i] << 21) | CAN_ID_STD | CAN_RTRQ_DATA); //!< 要过滤的ID低位

            CAN_FilterInitStructure.FilterMask_HighId     = 0xFFFF; //!< 过滤器高16位每位必须匹配
            CAN_FilterInitStructure.FilterMask_LowId      = 0xFFFF; //!< 过滤器低16位每位必须匹配
            CAN_FilterInitStructure.Filter_FIFOAssignment = CAN_FIFO0;
            CAN_FilterInitStructure.Filter_Act            = ENABLE;

            CAN1_InitFilter(&CAN_FilterInitStructure);
        }

        CAN_INTConfig(CAN1, CAN_INT_FMP0, ENABLE);
    }
}

/**
 * @brief Low Power Configuration.
 *
 * @param None
 * @retval None
 */
void CAN1_LP_Configuration(void)
{
    /* PB8 --- CAN1_RX */
    /* PB9 --- CAN1_TX */
    GPIO_InitType GPIO_InitStructure;

    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB, ENABLE);

    GPIO_InitStructure.Pin = GPIO_PIN_8 | GPIO_PIN_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_INPUT;
    GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);

    /* Remap CAN1 GPIOs: CAN1_RMP[1:0] = 10 */
    GPIO_ConfigPinRemap(GPIO_RMP2_CAN1, ENABLE);

    NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn); //!< interrupt disabled

}

/**
 * @brief Configures the CAN1.
 *
 * @param None
 * @retval None
 */
void CAN1_Configuration(struct __CAN_DriverTypeDef *dcan)
{
    CAN_InitType CAN_InitStructure;
    GPIO_InitType GPIO_InitStructure;
    NVIC_InitType NVIC_InitStructure;

    memcpy((unsigned char *)&can1_driver, (unsigned char *)dcan, sizeof(struct __CAN_DriverTypeDef));

    /* Configures CAN1.IOs */
    GPIO_InitStruct(&GPIO_InitStructure);

    /* PB8 --- CAN1_RX */
    /* PB9 --- CAN1_TX */
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_AFIO | RCC_APB2_PERIPH_GPIOB, ENABLE);

    /* Configure CAN1 RX pin */
    GPIO_InitStructure.Pin       = GPIO_PIN_8;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);

    /* Configure CAN1 TX pin */
    GPIO_InitStructure.Pin        = GPIO_PIN_9;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitPeripheral(GPIOB, &GPIO_InitStructure);

    /* Remap CAN1 GPIOs: CAN1_RMP[1:0] = 10 */
    GPIO_ConfigPinRemap(GPIO_RMP2_CAN1, ENABLE);

    /* Configure CAN1 */
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_CAN1, ENABLE);

    /* CAN1 register init */
    CAN_DeInit(CAN1);

    /* Struct init*/
    CAN_InitStruct(&CAN_InitStructure);

    /* CAN1 cell init */
    CAN_InitStructure.TTCM          = DISABLE; //!< [禁止] 时间触发: CAN硬件的内部定时器被激活，并且被用于产生时间戳
    CAN_InitStructure.ABOM          = DISABLE; //!< [禁止] 自动离线: 一旦硬件监控到128次11个隐性位，就自动退出离线状态。
    CAN_InitStructure.AWKUM         = DISABLE; //!< [禁止] 自动唤醒: 有报文来的时候自动退出休眠
    CAN_InitStructure.NART          = DISABLE; //!< 报文重传: 如果报文传输错误一直传到成功止，否则只传一次
    CAN_InitStructure.RFLM          = DISABLE; //!< 接收FIFO锁定: 0-接收到新的报文则覆盖前一报文  1-锁定后接收到新的报文摘不要
    CAN_InitStructure.TXFP          = ENABLE;  //!< 发送优先级:   0-由标识符决定                 1-由发送请求顺序决定
    CAN_InitStructure.OperatingMode = CAN_OPERATING_MODE;
    CAN_InitStructure.RSJW          = CAN_BIT_RSJW;
    CAN_InitStructure.TBS1          = CAN_BIT_BS1;
    CAN_InitStructure.TBS2          = CAN_BIT_BS2;
    CAN_InitStructure.BaudRatePrescaler = CAN_BAUDRATE_PRESCALER;

    /* Initializes the CAN1 */
    CAN_Init(CAN1, &CAN_InitStructure);

    CAN1_Filter_Init(can1_driver.FilterID, can1_driver.FilterID_Num);

    /* IT Configuration for CAN1 */
    CAN_INTConfig(CAN1, CAN_INT_FMP0, ENABLE);

    /* Configures the NVIC for CAN1_RX0 */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

    NVIC_InitStructure.NVIC_IRQChannel                   = USB_LP_CAN1_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0x00;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

}
